home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / info-service / gopher / incoming / gopher-1.1x-noPASV.patch < prev    next >
Encoding:
Text File  |  1993-06-01  |  15.3 KB  |  519 lines

  1.  
  2. These are some patches for the V1.1 and V1.12 gopherd so it can talk to
  3. FTP servers that do not understand the PASV command.
  4.  
  5. It also can tell directories from files from file-listings issued by some
  6. VMS FTP servers.
  7.  
  8. This has been tested with:
  9.     - one VMS FTP server running Wollongong-FTP V 5.1,
  10.     - one VMS FTP server running Multinet-FTP V 3.1.
  11.     - one Ultrix-RISC FTP server running 4.2 and one with 4.1,
  12.     - boombox.micro.umn.edu, which seems to be a Mac running some
  13.       version of A/UX.
  14.  
  15. Apparently, Multinet 3.2 does understand the PASV command, but this will
  16. not help, since the format of directory listings is still not what the
  17. original gopherd expects.
  18.  
  19.  
  20. To apply this patch:
  21.  
  22. Gopher 1.12: cd to the gopher1.12 directory and say: patch -p < thisfile
  23. Gopher 1.1 : cd to the gopher1.1  directory and say: patch -p -F3 < thisfile
  24.  
  25. (You will get some "with fuzz n" and "offset n lines" messages with gopher1.1,
  26. ignore these).
  27.  
  28. Patched files are: object/GSgopherobj.c gopherd/ftp.c gopherd/gopherd.c
  29.  
  30. Then rebuild gopherlib.a and gopherd:
  31.  
  32.     % rm object/gopherlib.a
  33.     % make server
  34.  
  35.  
  36. To use the extensions for VMS FTP servers, you must say:
  37.  
  38.         Path=ftp-vms:vms.ftp.server@/
  39.  
  40. and for Ultrix or A/UX FTP servers ("nop" stands for "no-PASV"):
  41.  
  42.     Path=ftp-nop:ultrix.ftp.serv@/
  43.  
  44. where you would usually write
  45.  
  46.         Path=ftp:unix.ftp.server@/
  47.  
  48. in a .Links file.
  49.  
  50. +-----------
  51.   Andi Karrer, Communication Systems, ETH Zuerich, Switzerland
  52.   karrer@bernina.ethz.ch    - Objects in mirror are closer than they appear
  53. +-----------
  54.  
  55. *** object/GSgopherobj.c.dist    Mon Jan 11 20:54:22 1993
  56. --- object/GSgopherobj.c    Sun Feb 21 23:11:49 1993
  57. ***************
  58. *** 1,3 ****
  59. --- 1,10 ----
  60. + /*
  61. +  * Added support for VMS FTP servers that do not understand the FTP PASV
  62. +  * command (Wollongong, Multinet). Also present these servers output
  63. +  * in a Unix fashion.
  64. +  * Also works with Ultrix 4.2 FTP servers whose PASV command is broken.
  65. +  * Andi Karrer, karrer@bernina.ethz.ch, 21. Feb 93
  66. +  */
  67.   /********************************************************************
  68.    * $Author: lindner $
  69.    * $Revision: 1.1.1.3 $
  70. ***************
  71. *** 408,413 ****
  72. --- 415,499 ----
  73.         closenet(iSock);
  74.         return (-4);
  75.        }
  76. +      return(iSock);
  77. + }
  78. + /* needed for FTP servers without PASV */
  79. + #include <errno.h>
  80. + /* GSlisten opens a port and listens to it */
  81. + int
  82. + GSlisten(We)
  83. +     struct sockaddr_in *    We;
  84. + {
  85. +      int iSock = 0;
  86. +      struct hostent *HostPtr;
  87. +      int len = sizeof(struct sockaddr_in);
  88. +      char name[100];
  89. +      if ((iSock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  90. +       return (-3);
  91. +      /* Cargo cult; no idea if these options are good here */
  92. + #ifndef UCX
  93. +      setsockopt(iSock, SOL_SOCKET, ~SO_LINGER, 0, 0);
  94. + #endif
  95. +      setsockopt(iSock, SOL_SOCKET, SO_REUSEADDR, 0, 0);
  96. +      setsockopt(iSock, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
  97. +      if (listen(iSock, 5) || getsockname(iSock, We, &len)) {
  98. +           closenet(iSock);
  99. +           return(-4);
  100. +      }
  101. +      gethostname(name, 100);
  102. +      if (HostPtr = gethostbyname(name)) 
  103. +           bcopy(HostPtr->h_addr, (char *) &We->sin_addr, HostPtr->h_length);
  104. +      return(iSock);
  105. + }
  106. + /* GSaccept accepts a connection from some socket. The parameter 
  107. +  * full_hostname will, on return,
  108. +  * contain the expanded hostname (if possible).  Note that full_hostname is a
  109. +  * pointer to a char *, and is allocated by connect_to_gopher()
  110. +  *
  111. +  * Errors:
  112. +  *
  113. +  * -1 get service failed
  114. +  *
  115. +  * -2 get host failed
  116. +  *
  117. +  * -3 socket call failed
  118. +  *
  119. +  * -4 connect call failed
  120. +  */
  121. + int
  122. + GSaccept(s, gs)
  123. +   int s;
  124. +   GopherObj *gs;
  125. + {
  126. +      struct sockaddr_in Server;
  127. +      struct hostent *HostPtr;
  128. +      int ERRinet = -1;
  129. +      int iSock = 0;
  130. +      int len = sizeof(struct sockaddr_in);
  131. + #ifdef _CRAY
  132. +      ERRinet = 0xFFFFFFFF;  /* -1 doesn't sign extend on 64 bit machines */
  133. + #endif
  134. +      if ((iSock = accept(s, &Server, &len)) < 0) {
  135. +     printf("Aaaargh! %d", errno);
  136. +        return -4;
  137. +      }
  138. +      
  139. +      GSsetPort(gs, ntohs(Server.sin_port));
  140. +      
  141. +      close(s); /* Der Mohr hat seine Schuldigkeit getan */
  142.        return(iSock);
  143.   }
  144.   
  145. *** gopherd/ftp.c.dist    Tue Jan 12 00:16:39 1993
  146. --- gopherd/ftp.c    Sun Feb 21 23:12:01 1993
  147. ***************
  148. *** 1,3 ****
  149. --- 1,10 ----
  150. + /*
  151. +  * Added support for VMS FTP servers that do not understand the FTP PASV
  152. +  * command (Wollongong, Multinet). Also present these servers output
  153. +  * in a Unix fashion.
  154. +  * Also works with Ultrix 4.2 FTP servers whose PASV command is broken.
  155. +  * Andi Karrer, karrer@bernina.ethz.ch, 21. Feb 93
  156. +  */
  157.   /********************************************************************
  158.    * $Author: lindner $
  159.    * $Revision: 1.2 $
  160. ***************
  161. *** 62,67 ****
  162. --- 69,76 ----
  163.   int    gettingBinary = 0;
  164.   int    childpid;
  165.   
  166. + extern int  no_pasv, is_vms;
  167.   /*** Some forward declarations ***/
  168.   boolean NotText();
  169.   int     Abort();
  170. ***************
  171. *** 323,329 ****
  172.         while (fgets(buf, sizeof buf, fp) != NULL) {
  173.              ZapCRLF(buf);
  174.              GopherType(buf, theName);
  175. !            sprintf(outputline, "%s\tftp:%s@%s%s\t%s\t%d\r\n", theName,
  176.                  host, thing, buf, Zehostname, GopherPort);
  177.              FailErr(writestring(sockfd, outputline));
  178.         }
  179. --- 332,339 ----
  180.         while (fgets(buf, sizeof buf, fp) != NULL) {
  181.              ZapCRLF(buf);
  182.              GopherType(buf, theName);
  183. !            sprintf(outputline, "%s\t%s:%s@%s%s\t%s\t%d\r\n", theName,
  184. !                no_pasv ? is_vms ? "ftp-vms" : "ftp-nop" : "ftp", 
  185.                  host, thing, buf, Zehostname, GopherPort);
  186.              FailErr(writestring(sockfd, outputline));
  187.         }
  188. ***************
  189. *** 430,438 ****
  190.        int extType, i, last;
  191.        char    tmpName[SLEN];    
  192.        
  193. !      last = strlen(buf) -1;
  194.        strcpy(tmpName, buf);
  195.        if (buf[last] == '/') {
  196.         tmpName[last] = '\0';
  197.         sprintf(theName, "%d%s", GDIR, tmpName);
  198. --- 440,468 ----
  199.        int extType, i, last;
  200.        char    tmpName[SLEN];    
  201.        
  202. !      last = strlen(buf) - 1;
  203. !      while (buf[last] == ' ') {
  204. !         buf[last] = '\0';
  205. !         last--;
  206. !      }
  207. !      if (is_vms) {
  208. !           /* strip ugly VMS version numbers */
  209. !           last = strlen(buf) - 1;
  210. !           while(last>1 && isdigit(buf[last])) last--;
  211. !           if (last>1 && buf[last] == ';') {
  212. !                buf[last] = '\0';
  213. !                last--;
  214. !           }
  215. !      }
  216.        strcpy(tmpName, buf);
  217. +      /* if buf ends in ".dir", it's a directory, replace ".dir" with "/" */
  218. +      if (is_vms && (last > 3) && (strncmp(buf + last - 3, ".dir", 4) == 0)) {
  219. +           last -= 3;
  220. +           tmpName[last] = '\0';
  221. +           sprintf(buf, "%s/", tmpName);
  222. +           sprintf(theName, "%d%s", GDIR, tmpName);
  223. +           return;
  224. +      }
  225.        if (buf[last] == '/') {
  226.         tmpName[last] = '\0';
  227.         sprintf(theName, "%d%s", GDIR, tmpName);
  228. ***************
  229. *** 521,523 ****
  230. --- 551,758 ----
  231.   }
  232.   
  233.   /*--------------------------------*/
  234. + void
  235. + SendNoPASVFtpQuery(sockfd, query)
  236. +   char *query;
  237. + {
  238. +      int       sLen, termCh, i;
  239. +      char      *at, *cp;
  240. +      char      inputline[512];
  241. +      char      buf[1600];     /*** Nice MTU size ***/
  242. +      int       tmpfd;
  243. +      int       ftp_control, ftp_data;
  244. +      int       ftp_dataport, nRead;
  245. +      GopherObj *gs;
  246. +      struct sockaddr_in we;
  247. +      char vmspath[256], vmsfile[80];
  248. +      char *beg, *end;
  249. +      int len;
  250. +      int makelower;
  251. +      /*** hook onto the gs code to do our ftp socket connects ***/
  252. +      gs = GSnew();
  253. +      /** Get ready for some cleanup action **/
  254. +      signal(SIGPIPE, Cleanup);
  255. +      signal(SIGINT, Cleanup);
  256. +      signal(SIGALRM, Cleanup);
  257. +      if (DEBUG) printf("The full query was %s\n", query);
  258. +      
  259. +      if ((sLen = strlen(query)) <= 2) Abort(sockfd,"No host name specified.");
  260. +      host = query;
  261. +      at = strchr(query, '@');
  262. +      
  263. +      if (at == NULL) Abort(sockfd, "Not a valid ftp query.");
  264. +      
  265. +      GenerateUniqueFiles(ftptmp);
  266. +      tmpfd = uopen(ftptmp, O_RDWR|O_CREAT,0755);
  267. +      
  268. +      if (tmpfd < 0)
  269. +       Abort(sockfd, "Sorry, out of tmp transfer space!");
  270. +      thing = at + 1;
  271. +      *at = '\0';             /*Sneakily chop it into two strings*/
  272. +      sLen = strlen(thing);
  273. +      termCh = thing[sLen - 1];            /* Grab possible end char: / etc */
  274. +      
  275. +      if ((termCh == '*') || (termCh == '@'))  /*  || (termCh == '/')  */
  276. +       thing[sLen - 1] = '\0';
  277. +      
  278. +      if (DEBUG)
  279. +       printf("At this point host: %s   thing: %s\n", host, thing);
  280. +      
  281. +      /*** Open an ftp control connection ***/
  282. +      GSsetHost(gs, host);
  283. +      GSsetPort(gs, 21);
  284. +      
  285. +      ftp_control = GSconnect(gs);
  286. +      if (ftp_control < 0)
  287. +       Abort(sockfd, "unable to connect to ftp server!");
  288. +      /*** Strip off the connection message ***/
  289. +      getreply(ftp_control,inputline,sizeof inputline);
  290. +      if (*inputline != '2')
  291. +       /*** Some sort of error, urg! ***/
  292. +       Abort(sockfd, inputline +3);
  293. +      /*** Send username ***/
  294. +      writestring(ftp_control, "USER anonymous\r\n");
  295. +      if (DEBUG) printf("Send: USER anonymous CRLF\n");
  296. +      getreply(ftp_control,inputline,sizeof inputline);
  297. +      if (*inputline != '3')
  298. +       /*** Some sort of error, urg! ***/
  299. +       Abort(sockfd, inputline +3);
  300. +      /** Send password***/
  301. +      writestring(ftp_control, "PASS -gopher@");
  302. +      writestring(ftp_control, Zehostname);
  303. +      writestring(ftp_control, "\r\n");
  304. +      if (DEBUG) printf("Send: PASS -gopher@%s\n", Zehostname);
  305. +      getreply(ftp_control,inputline,sizeof inputline);
  306. +      if (*inputline != '2')
  307. +       /*** Some sort of error, urg! ***/
  308. +       Abort(sockfd, inputline +3);
  309. +      if ((ftp_dataport = GSlisten(&we)) < 0)
  310. +        Abort(sockfd, "no clue what socket error!");
  311. +      sprintf(inputline, "PORT %d,%d,%d,%d,%d,%d\r\n",
  312. +          (htonl(we.sin_addr.s_addr) >> 24) & 0xFF,
  313. +          (htonl(we.sin_addr.s_addr) >> 16) & 0xFF,
  314. +          (htonl(we.sin_addr.s_addr) >>  8) & 0xFF,
  315. +          (htonl(we.sin_addr.s_addr)      ) & 0xFF,
  316. +          (htons(we.sin_port)        >>  8) & 0xFF,
  317. +          (htons(we.sin_port)             ) & 0xFF);
  318. +      if (DEBUG) printf("Send: %s", inputline);
  319. +      writestring(ftp_control, inputline);
  320. +      getreply(ftp_control,inputline,sizeof inputline);
  321. +      if (*inputline != '2')
  322. +       /*** Some sort of error, urg! ***/
  323. +       Abort(sockfd, inputline +3);
  324. +      if (termCh == '/') {    /* We have a directory */
  325. +           if (DEBUG) printf("(It's a directory)\n");
  326. +       gettingFile = 0;
  327. +           /* thing looks like '/dir/dir.../dir/' now. Because Wollongong
  328. +            * wants "CWD dir/dir/dir" and Multinet wants "CWD dir.dir.dir"
  329. +            * we do the CWD in a stepwise fashion. Oh well...
  330. +            */
  331. +           beg = thing + 1;
  332. +       while (beg < thing + strlen(thing) - 2) {
  333. +                end = strchr(beg, '/');
  334. +                strcpy(vmspath, beg);
  335. +                vmspath[end-beg] = '\0';
  336. +            writestring(ftp_control, "CWD ");
  337. +            writestring(ftp_control, vmspath);
  338. +            writestring(ftp_control, "\r\n");
  339. +                if (DEBUG) printf("Send: CWD %s CRLF\n", vmspath);
  340. +            getreply(ftp_control,inputline,sizeof inputline);
  341. +            if (*inputline != '2')
  342. +                 Abort(sockfd,inputline + 4);
  343. +                beg = end + 1;
  344. +       }
  345. +           if (DEBUG) printf("Send: %s\n", is_vms ? "NLST" : "NLST -LF");
  346. +       writestring(ftp_control, is_vms ? "NLST\r\n" : "NLST -LF\r\n");
  347. +       getreply(ftp_control,inputline,sizeof inputline);
  348. +           makelower = 1;
  349. +       if (*inputline != '1')
  350. +            Abort(sockfd,inputline + 4);
  351. +      }
  352. +      else {                    /* We have a file */
  353. +           if (DEBUG) printf("(It's a file)\n");
  354. +       gettingFile = 1;
  355. +       if (gettingBinary = IsBinaryType(thing))  {
  356. +            writestring(ftp_control, "TYPE I\r\n");
  357. +                if (DEBUG) printf("Send: TYPE I\n");
  358. +            getreply(ftp_control,inputline,sizeof inputline);
  359. +            if (*inputline != '2')
  360. +             Abort(sockfd,"Unable to transfer files in binary");
  361. +       }
  362. +       /* thing now looks like '/dir/dir/file.ext' */
  363. +       strcpy(vmspath, thing);
  364. +       len = strlen(vmspath) - 1;
  365. +       while (len > 1 && vmspath[len] != '/') len--;
  366. +           beg = vmspath + 1;
  367. +       while ((end = strchr(beg, '/')) != NULL) {
  368. +                strcpy(vmsfile, beg);
  369. +                vmsfile[end-beg] = '\0';
  370. +            writestring(ftp_control, "CWD ");
  371. +            writestring(ftp_control, vmsfile);
  372. +            writestring(ftp_control, "\r\n");
  373. +                if (DEBUG) printf("Send: CWD %s CRLF\n", vmsfile);
  374. +            getreply(ftp_control,inputline,sizeof inputline);
  375. +                if (*inputline != '2')
  376. +                     Abort(sockfd,inputline + 4);
  377. +                beg = end + 1;
  378. +           }
  379. +           beg = strrchr(thing, '/') + 1;
  380. +       writestring(ftp_control, "RETR ");
  381. +       writestring(ftp_control, beg);
  382. +       writestring(ftp_control, "\r\n");
  383. +           if (DEBUG) printf("Send: RETR %s CRLF\n", beg);
  384. +           makelower = 0;
  385. +       getreply(ftp_control,inputline,sizeof inputline);
  386. +       if (*inputline != '1')
  387. +            Abort(sockfd,inputline + 4);
  388. +      }
  389. +      ftp_data = GSaccept(ftp_dataport, gs);
  390. +      if (ftp_data < 0)
  391. +       Abort(sockfd,"Unable to establish data connection!");
  392. +      /*** Transfer the data... ***/
  393. +      while ((nRead = read(ftp_data, buf, sizeof buf)) > 0) {
  394. +       if (makelower && is_vms) {
  395. +         for (i=0; i<nRead; i++) buf[i] = tolower(buf[i]);
  396. +           }
  397. +       writen(tmpfd, buf, nRead);
  398. +      }
  399. +      close(ftp_data);
  400. +      
  401. +      getreply(ftp_control,inputline,sizeof inputline);
  402. +      if (*inputline != '2')
  403. +       Abort(sockfd,inputline + 3);
  404. +      writestring(ftp_control, "QUIT\r\n");
  405. +      getreply(ftp_control,inputline,sizeof inputline);
  406. +      if (*inputline != '2')
  407. +       Abort(sockfd,inputline + 3);
  408. +      close(ftp_control);
  409. + }
  410. *** gopherd/gopherd.c.dist    Mon Jan 11 20:07:42 1993
  411. --- gopherd/gopherd.c    Sun Feb 21 23:12:13 1993
  412. ***************
  413. *** 1,3 ****
  414. --- 1,10 ----
  415. + /*
  416. +  * Added support for VMS FTP servers that do not understand the FTP PASV
  417. +  * command (Wollongong, Multinet). Also present these servers output
  418. +  * in a Unix fashion.
  419. +  * Also works with Ultrix 4.2 FTP servers whose PASV command is broken.
  420. +  * Andi Karrer, karrer@bernina.ethz.ch, 21. Feb 93
  421. +  */
  422.   /********************************************************************
  423.    * $Author: lindner $
  424.    * $Revision: 1.2.1.6 $
  425. ***************
  426. *** 56,61 ****
  427. --- 63,70 ----
  428.   void LOGGopher();
  429.   
  430.   static    int    uid = -2;
  431. + int no_pasv = 0;
  432. + int is_vms  = 0;
  433.   
  434.   extern char *getdesc();
  435.   extern double  maxload;
  436. ***************
  437. *** 655,660 ****
  438. --- 664,670 ----
  439.   do_command(sockfd)
  440.     int sockfd;
  441.   {
  442. +      extern int no_pasv;
  443.        char inputline[MAXLINE];
  444.        int length;        /* Length of the command line */
  445.        char logline[MAXLINE];
  446. ***************
  447. *** 916,921 ****
  448. --- 926,932 ----
  449.         }
  450.   
  451.         if (strncmp(selstr, "ftp:",4)==0){
  452. +                no_pasv = 0;
  453.              sprintf(logline, "retrieved %s", selstr);
  454.              LOGGopher(sockfd, logline);
  455.   
  456. ***************
  457. *** 923,928 ****
  458. --- 934,949 ----
  459.              TranslateResults(sockfd);
  460.              break;
  461.         }
  462. +           is_vms = (strncmp(selstr, "ftp-vms:",8) == 0);
  463. +           if ((is_vms) || (strncmp(selstr, "ftp-nop:",8) == 0)) {
  464. +                no_pasv = 1;
  465. +            sprintf(logline, "retrieved %s", selstr);
  466. +            LOGGopher(sockfd, logline);
  467. +                SendNoPASVFtpQuery(sockfd, selstr+8);
  468. +                TranslateResults(sockfd);
  469. +                break;
  470. +           }
  471.         break;
  472.   
  473.        case 'e':
  474.